/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package caro;

import binh.CCommon;
import binh.CClient;
import binh.CGameLogic;
import binh.CTable;
import binh.ILoopable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import we.common.CDebug;
import we.dispatcher.CPacketReader;
import we.dispatcher.CPacketWriter;

/**
 *
 * @author ADMIN
 */
public class CCaroLogic extends CGameLogic implements ILoopable
{

    public final static int MT_CARO_SET_TURN = 350;
    public final static int MT_CARO_GAME_RESULT = 351;
    public final static int MT_CARO_REQUEST_PUT_CELL = 352;
    public final static int MT_CARO_PUT_CELL = 353;
    public final static int MT_CARO_REQUEST_ASK_LOSE = 354;
    public final static int MT_CARO_ASK_LOSE = 355;
    public final static int MT_CARO_REQUEST_ASK_EQUAL = 356;
    public final static int MT_CARO_ASK_EQUAL = 357;
    public final static int MT_CARO_REQUEST_ACCEPT_ASK_EQUAL = 358;
    public final static int MT_CARO_ACCEPT_ASK_EQUAL = 359;
    public final static int TIME_CARO_SET_TURN = 15;
    public final static int TIME_CARO_RESULT = 10;
    public final static int MAX_ROW = 20;
    public final static int MAX_COLUMN = 20; 
    public int[] CaroResult;
    public int CellLast = -1;
    public int IsTurn = -1;
    public boolean AskEqual = false;
    public int EndGamePoint = -1;
    public int TypeLine = -1;
    public List<Integer> ListCellWin = new ArrayList<Integer>();
    public int NumberClient = 2;
    private Random random = new Random();

    public CCaroLogic(CTable Table)
    {
        super(Table);
        CaroResult = new int[MAX_COLUMN * MAX_ROW];
    }

    @Override
    public void StartGame()
    {
        Table.TimeGame = 0;
        Table.TimeStage = 0;
        CellLast = -1;
        NumberClient = 2;
        AskEqual = false;
        ListCellWin.clear();

        for (int i = 0; i < MAX_COLUMN * MAX_ROW; i++)
        {
            CaroResult[i] = -1;
        }

        // Turn
        if (Table.Turn == null)
        {
            Table.Turn = Table.Owner;
        }

        Table.SetGameStage(CCommon.GS_PLAYING, 0);
        SetTurn(Table.Turn);

        //SendStartGame();
    }

    // Set turn
    public void SetTurn(CClient Client)
    {
        Table.Turn = Client;
        Table.TimeTurn = TIME_CARO_SET_TURN;

        // Send
        CPacketWriter SendPacket = new CPacketWriter();
        SendPacket.PutID(MT_CARO_SET_TURN);
        SendPacket.PutInt(Client.GetClientIndex());
        SendPacket.PutInt(Table.TimeTurn);
        SendPacket.PutLengthAndFlip();
        Table.SendAll(SendPacket);
    }

    @Override
    public void OnTimer(int delta)
    {
        try
        {
            if (Table.GameStage == CCommon.GS_WAITING_ROOM)
            {
                return;
            }

            if (Table.GameStage == CCommon.GS_PLAYING)
            {
                if (Table.TimeTurn > 0)
                {
                    Table.TimeTurn--;

                    if (Table.TimeTurn == 0)
                    {
                        ProcessTimeout();
                    }
                }
            }

            if (Table.GameStage == CCommon.GS_RESULT)
            {
                if (Table.TimeStage > 0)
                {
                    Table.TimeStage--;

                    if (Table.TimeStage == 0)
                    {
                        Table.SetGameStage(CCommon.GS_WAITING_ROOM, 0);
                        Table.KickPoorClient();
                    }
                }
            }
        } catch (Exception ex)
        {
            CDebug.Error(this, ex);
        }
    }

    // Timeout
    public void ProcessTimeout()
    {
        if (Table.Turn == null)
        {
            return;
        }

        ProcessAutoPutCell();
    }

    public int GetCellAuto(int xLast, int yLast)
    {
        CDebug.Trace(this, "GetCellAuto Start");
        if (CellLast == -1)
        {
            int x2 = MAX_COLUMN / 2;
            int y2 = MAX_COLUMN / 2;

            while (CaroResult[y2 * MAX_COLUMN + x2] != -1)
            {
                x2 = random.nextInt(MAX_COLUMN);
                y2 = random.nextInt(MAX_COLUMN);
            }
            CDebug.Trace(this, "GetCellAuto Finish CellLast = -1");
            return (y2 * MAX_COLUMN + x2);
        }

        int j = random.nextInt(8);
        CDebug.Trace(this, "j === " + j);

        int x = 0;
        int y = 0;

        //j = 5;

        switch (j)
        {
            case 0:
                // Check sang phải
                for (int i = xLast + 1; i < MAX_COLUMN; i++)
                {
                    x = i;
                    y = yLast;
                    if (CaroResult[y * MAX_COLUMN + x] == -1)
                    {
                        CDebug.Trace(this, "GetCellAuto Finish Phai");
                        return (y * MAX_COLUMN + x);
                    }
                }
                break;
            case 4:
                // Check sang trái
                for (int i = xLast - 1; i >= 0; i--)
                {
                    x = i;
                    y = yLast;
                    if (CaroResult[y * MAX_COLUMN + x] == -1)
                    {
                        CDebug.Trace(this, "GetCellAuto Finish Trai");
                        return (y * MAX_COLUMN + x);
                    }
                }
                break;

            case 2:
                // Check xuống dưới
                for (int i = yLast + 1; i < MAX_ROW; i++)
                {
                    x = xLast;
                    y = i;
                    if (CaroResult[y * MAX_COLUMN + x] == -1)
                    {
                        CDebug.Trace(this, "GetCellAuto Finish Xuong");
                        return (y * MAX_COLUMN + x);
                    }
                }
                break;

            case 6:
                // Check lên trên
                for (int i = yLast - 1; i >= 0; i--)
                {
                    x = xLast;
                    y = i;
                    if (CaroResult[y * MAX_COLUMN + x] == -1)
                    {
                        CDebug.Trace(this, "GetCellAuto Finish Len");
                        return (y * MAX_COLUMN + x);
                    }
                }
                break;
            case 1:
                // Check phải xuống
                x = xLast + 1;
                y = yLast + 1;
                while (x < MAX_COLUMN && y < MAX_COLUMN)
                {
                    if (CaroResult[y * MAX_COLUMN + x] == -1)
                    {
                        CDebug.Trace(this, "GetCellAuto Finish Phai Xuong");
                        return (y * MAX_COLUMN + x);
                    }
                    x++;
                    y++;
                }
                break;
            case 3:
                // Check trái xuống
                x = xLast - 1;
                y = yLast + 1;
                while (x >= 0 && y < MAX_COLUMN)
                {
                    if (CaroResult[y * MAX_COLUMN + x] == -1)
                    {
                        CDebug.Trace(this, "GetCellAuto Finish Trai Xuong");
                        return (y * MAX_COLUMN + x);
                    }
                    x--;
                    y++;
                }
                break;
            case 5:
                // Check trái lên
                x = xLast - 1;
                y = yLast - 1;
                while (x >= 0 && y >= 0)
                {
                    if (CaroResult[y * MAX_COLUMN + x] == -1)
                    {
                        CDebug.Trace(this, "GetCellAuto Finish Trai Len");
                        return (y * MAX_COLUMN + x);
                    }
                    x--;
                    y--;
                }
                break;
            case 7:
                // Check phải lên
                x = xLast + 1;
                y = yLast - 1;
                while (x < MAX_COLUMN && y >= 0)
                {
                    if (CaroResult[y * MAX_COLUMN + x] == -1)
                    {
                        CDebug.Trace(this, "GetCellAuto Finish Phai Len");
                        return (y * MAX_COLUMN + x);
                    }
                    x++;
                    y--;
                }
                break;
        }
        int x1 = xLast;
        int y1 = yLast;

        while (CaroResult[y1 * MAX_COLUMN + x1] != -1)
        {
            x1 = random.nextInt(MAX_COLUMN);
            y1 = random.nextInt(MAX_COLUMN);
        }

        CDebug.Trace(this, "GetCellAuto Finish");
        return (y1 * MAX_COLUMN + x1);
    }

    public void ProcessAutoPutCell()
    {
        int x = 0;
        int y = 0;

        int xLast = 0;
        int yLast = 0;

        if (CellLast != -1)
        {
            xLast = CellLast % MAX_COLUMN;
            yLast = CellLast / MAX_COLUMN;
        } else
        {
            xLast = 0;
            yLast = 0;
        }

        int Cell = GetCellAuto(xLast, yLast);
        CellLast = Cell;


        x = Cell % MAX_COLUMN;
        y = Cell / MAX_COLUMN;

        CDebug.Trace(this, " x === " + x);
        CDebug.Trace(this, " y === " + y);

        if (Table.Turn.GetClientIndex() == Table.Owner.GetClientIndex())
        {
            IsTurn = 1;
            CaroResult[y * MAX_COLUMN + x] = 1;
        } else
        {
            IsTurn = 0;
            CaroResult[y * MAX_COLUMN + x] = 0;
        }

        CPacketWriter SendPacket = new CPacketWriter();
        SendPacket.PutID(MT_CARO_PUT_CELL);

        SendPacket.PutInt(Table.Turn.GetClientIndex());
        if (Table.Turn.GetClientIndex() == Table.Owner.GetClientIndex())
        {
            SendPacket.PutInt(1);
        } else
        {
            SendPacket.PutInt(0);
        }
        SendPacket.PutInt(x);
        SendPacket.PutInt(y);
        Table.SendAll(SendPacket);

        if (CheckEndGame(x, y, IsTurn))
        {
            EndGame();
            return;
        }

        CClient Next = Table.GetNextClient(Table.Turn);
        SetTurn(Next);
    }
    
    
    @Override
    public void OnReceive(CClient Client, int CmdId, CPacketReader Reader)
    {
     
        switch (CmdId)
        {
            case MT_CARO_REQUEST_PUT_CELL:
                ProcessPutCell(Client, Reader);
                break;
            case MT_CARO_REQUEST_ASK_LOSE:
                ProcessAskLose(Client, Reader);
                break;
            case MT_CARO_REQUEST_ASK_EQUAL:
                ProcessAskEqual(Client, Reader);
                break;
            case MT_CARO_REQUEST_ACCEPT_ASK_EQUAL:
                ProcessAcceptAskEqual(Client, Reader);
                break;
        }
    }

    public void ProcessAcceptAskEqual(CClient Client, CPacketReader Packet)
    {
        AskEqual = false;
        int Equal = Packet.GetInt();
        CPacketWriter PacketSend = new CPacketWriter();
        PacketSend.PutID(MT_CARO_ACCEPT_ASK_EQUAL);
        PacketSend.PutInt(Client.GetClientIndex());
        if (Equal == 1)
        {
            PacketSend.PutInt(1);
        } else
        {
            PacketSend.PutInt(0);
        }
        Table.SendAll(PacketSend);
        if (Equal == 1)
        {
            IsTurn = -1;
            EndGame();
        }
    }

    public void ProcessAskEqual(CClient Client, CPacketReader Packet)
    {
        if (AskEqual)
        {
            return;
        }
        CPacketWriter PacketSend = new CPacketWriter();
        PacketSend.PutID(MT_CARO_ASK_EQUAL);
        PacketSend.PutInt(Client.GetClientIndex());
        PacketSend.PutLengthAndFlip();
        Table.SendAll(PacketSend);
        AskEqual = true;
    }

    public void ProcessAskLose(CClient Client, CPacketReader Packet)
    {
        if (Client.GetClientIndex() == Table.Owner.GetClientIndex())
        {
            IsTurn = 0;
        } else
        {
            IsTurn = 1;
        }
        CPacketWriter PacketSend = new CPacketWriter();
        PacketSend.PutID(MT_CARO_ASK_LOSE);
        PacketSend.PutInt(Client.GetClientIndex());
        PacketSend.PutLengthAndFlip();
        Table.SendAll(PacketSend);
        EndGame();
    }

    public void ProcessPutCell(CClient Client, CPacketReader Packet)
    {
        if (Client.GetClientIndex() != Table.Turn.GetClientIndex())
        {
            return;
        }

        int x = Packet.GetInt();
        int y = Packet.GetInt();
        CDebug.Trace(this, " x === " + x);
        CDebug.Trace(this, " y === " + y);
        CellLast = y * MAX_COLUMN + x;

        if (Table.Turn.GetClientIndex() == Table.Owner.GetClientIndex())
        {
            IsTurn = 1;
            CaroResult[y * MAX_COLUMN + x] = 1;
        } else
        {
            IsTurn = 0;
            CaroResult[y * MAX_COLUMN + x] = 0;
        }

        CPacketWriter SendPacket = new CPacketWriter();
        SendPacket.PutID(MT_CARO_PUT_CELL);

        SendPacket.PutInt(Table.Turn.GetClientIndex());
        if (Table.Turn.GetClientIndex() == Table.Owner.GetClientIndex())
        {
            SendPacket.PutInt(1);
        } else
        {
            SendPacket.PutInt(0);
        }
        SendPacket.PutInt(x);
        SendPacket.PutInt(y);
        SendPacket.PutLengthAndFlip();
        Table.SendAll(SendPacket);

        if (CheckEndGame(x, y, IsTurn))
        {
            EndGame();
            return;
        }

        CClient Next = Table.GetNextClient(Client);
        SetTurn(Next);
    }

    // Check End Game
    public boolean CheckEndGame(int x, int y, int IsOwner)
    {
        // Check hang ngang
        for (int i = x - 4; i < x + 1; i++)
        {
            if (i < 0 || i + 4 >= MAX_COLUMN)
            {
                continue;
            }
            if (CaroResult[y * MAX_COLUMN + i] == IsOwner
                    && CaroResult[y * MAX_COLUMN + i + 1] == IsOwner
                    && CaroResult[y * MAX_COLUMN + i + 2] == IsOwner
                    && CaroResult[y * MAX_COLUMN + i + 3] == IsOwner
                    && CaroResult[y * MAX_COLUMN + i + 4] == IsOwner)
            {
                if (i == 0)
                {
                    if (CaroResult[y * MAX_COLUMN + i + 5] == IsOwner)
                    {
                        continue;
                    }
                    TypeLine = 2;
                    EndGamePoint = y * MAX_COLUMN + i;
                    int k = i;
                    while (k < MAX_COLUMN)
                    {
                        if (CaroResult[y * MAX_COLUMN + k] == IsOwner)
                        {
                            ListCellWin.add(y * MAX_COLUMN + k);
                            k++;
                        } else
                        {
                            break;
                        }
                    }
                    return true;
                }
                if (i + 5 == MAX_COLUMN)
                {
                    if (CaroResult[y * MAX_COLUMN + i - 1] == IsOwner)
                    {
                        continue;
                    }
                    TypeLine = 2;
                    EndGamePoint = y * MAX_COLUMN + i;
                    int k = i;
                    while (k < MAX_COLUMN)
                    {
                        if (CaroResult[y * MAX_COLUMN + k] == IsOwner)
                        {
                            ListCellWin.add(y * MAX_COLUMN + k);
                            k++;
                        } else
                        {
                            break;
                        }
                    }
                    return true;
                }

                if (CaroResult[y * MAX_COLUMN + i - 1] == IsOwner
                        || CaroResult[y * MAX_COLUMN + i + 5] == IsOwner)
                {
                    continue;
                }

                int j = i - 1;
                while (j >= 0)
                {
                    if (CaroResult[y * MAX_COLUMN + j] == -1)
                    {
                        TypeLine = 2;
                        EndGamePoint = y * MAX_COLUMN + i;
                        int k = i;
                        while (k < MAX_COLUMN)
                        {
                            if (CaroResult[y * MAX_COLUMN + k] == IsOwner)
                            {
                                ListCellWin.add(y * MAX_COLUMN + k);
                                k++;
                            } else
                            {
                                break;
                            }
                        }
                        return true;
                    }
                    if (CaroResult[y * MAX_COLUMN + j] != IsOwner)
                    {
                        break;
                    }
                    j--;
                }
                j = i + 5;
                while (j < MAX_COLUMN)
                {
                    if (CaroResult[y * MAX_COLUMN + j] == -1)
                    {
                        TypeLine = 2;
                        EndGamePoint = y * MAX_COLUMN + i;
                        int k = i;
                        while (k < MAX_COLUMN)
                        {
                            if (CaroResult[y * MAX_COLUMN + k] == IsOwner)
                            {
                                ListCellWin.add(y * MAX_COLUMN + k);
                                k++;
                            } else
                            {
                                break;
                            }
                        }
                        return true;
                    }
                    if (CaroResult[y * MAX_COLUMN + j] != IsOwner)
                    {
                        break;
                    }
                    j++;
                }
            }
        }

        // Check hang doc               
        for (int i = y - 4; i < y + 1; i++)
        {
            if (i < 0 || i + 4 >= MAX_ROW)
            {
                continue;
            }
            if (CaroResult[i * MAX_COLUMN + x] == IsOwner
                    && CaroResult[(i + 1) * MAX_COLUMN + x] == IsOwner
                    && CaroResult[(i + 2) * MAX_COLUMN + x] == IsOwner
                    && CaroResult[(i + 3) * MAX_COLUMN + x] == IsOwner
                    && CaroResult[(i + 4) * MAX_COLUMN + x] == IsOwner)
            {
                if (i == 0)
                {
                    if (CaroResult[(i + 5) * MAX_COLUMN + x] == IsOwner)
                    {
                        continue;
                    }
                    TypeLine = 0;
                    EndGamePoint = i * MAX_COLUMN + x;
                    int k = i;
                    while (k < MAX_COLUMN)
                    {
                        if (CaroResult[k * MAX_COLUMN + x] == IsOwner)
                        {
                            ListCellWin.add(k * MAX_COLUMN + x);
                            k++;
                        } else
                        {
                            break;
                        }
                    }
                    return true;
                }
                if (i + 5 == MAX_COLUMN)
                {
                    if (CaroResult[(i - 1) * MAX_COLUMN + x] == IsOwner)
                    {
                        continue;
                    }
                    TypeLine = 0;
                    EndGamePoint = i * MAX_COLUMN + x;
                    int k = i;
                    while (k < MAX_COLUMN)
                    {
                        if (CaroResult[k * MAX_COLUMN + x] == IsOwner)
                        {
                            ListCellWin.add(k * MAX_COLUMN + x);
                            k++;
                        } else
                        {
                            break;
                        }
                    }
                    return true;
                }

                if (CaroResult[(i + 5) * MAX_COLUMN + x] == IsOwner
                        || CaroResult[(i - 1) * MAX_COLUMN + x] == IsOwner)
                {
                    continue;
                }

                int j = i - 1;
                while (j >= 0)
                {
                    if (CaroResult[j * MAX_COLUMN + x] == -1)
                    {
                        TypeLine = 0;
                        EndGamePoint = i * MAX_COLUMN + x;
                        int k = i;
                        while (k < MAX_COLUMN)
                        {
                            if (CaroResult[k * MAX_COLUMN + x] == IsOwner)
                            {
                                ListCellWin.add(k * MAX_COLUMN + x);
                                k++;
                            } else
                            {
                                break;
                            }
                        }
                        return true;
                    }
                    if (CaroResult[j * MAX_COLUMN + x] != IsOwner)
                    {
                        break;
                    }
                    j--;
                }
                j = i + 5;
                while (j < MAX_COLUMN)
                {
                    if (CaroResult[j * MAX_COLUMN + x] == -1)
                    {
                        TypeLine = 0;
                        EndGamePoint = j * MAX_COLUMN + x;
                        int k = i;
                        while (k < MAX_COLUMN)
                        {
                            if (CaroResult[k * MAX_COLUMN + x] == IsOwner)
                            {
                                ListCellWin.add(k * MAX_COLUMN + x);
                                k++;
                            } else
                            {
                                break;
                            }
                        }
                        return true;
                    }
                    if (CaroResult[j * MAX_COLUMN + x] != IsOwner)
                    {
                        break;
                    }
                    j++;
                }
                //return true;
            }
        }

        // Check duong cheo tren xuong
        for (int i = x - 4; i < x + 1; i++)
        {
            if (i < 0 || i + 4 >= MAX_COLUMN)
            {
                continue;
            }

            int j = y + i - x;

            if (j < 0 || j + 4 >= MAX_ROW)
            {
                continue;
            }

            if (CaroResult[j * MAX_COLUMN + i] == IsOwner
                    && CaroResult[(j + 1) * MAX_COLUMN + i + 1] == IsOwner
                    && CaroResult[(j + 2) * MAX_COLUMN + i + 2] == IsOwner
                    && CaroResult[(j + 3) * MAX_COLUMN + i + 3] == IsOwner
                    && CaroResult[(j + 4) * MAX_COLUMN + i + 4] == IsOwner)
            {

                if (i == 0 || j == 0 || i + 5 == MAX_COLUMN || j + 5 == MAX_COLUMN)
                {
                    if (i == 0)
                    {
                        if (j < MAX_COLUMN - 5)
                        {
                            if (CaroResult[(j + 5) * MAX_COLUMN + i + 5] == IsOwner)
                            {
                                continue;
                            }
                        }
                    }

                    if (j == 0)
                    {
                        if (i < MAX_COLUMN - 5)
                        {
                            if (CaroResult[(j + 5) * MAX_COLUMN + i + 5] == IsOwner)
                            {
                                continue;
                            }
                        }
                    }

                    if (i + 5 == MAX_COLUMN)
                    {
                        if (j > 0)
                        {
                            if (CaroResult[(j - 1) * MAX_COLUMN + i - 1] == IsOwner)
                            {
                                continue;
                            }
                        }
                    }

                    if (j + 5 == MAX_COLUMN)
                    {
                        if (i > 0)
                        {
                            if (CaroResult[(j - 1) * MAX_COLUMN + i - 1] == IsOwner)
                            {
                                continue;
                            }
                        }
                    }

                    TypeLine = 1;
                    EndGamePoint = j * MAX_COLUMN + i;
                    int m = i;
                    int n = j;
                    while (m < MAX_COLUMN && n < MAX_COLUMN)
                    {
                        if (CaroResult[n * MAX_COLUMN + m] == IsOwner)
                        {
                            ListCellWin.add(n * MAX_COLUMN + m);
                            m++;
                            n++;
                        } else
                        {
                            break;
                        }
                    }
                    return true;
                }

                if (CaroResult[(j - 1) * MAX_COLUMN + i - 1] == IsOwner
                        || CaroResult[(j + 5) * MAX_COLUMN + i + 5] == IsOwner)
                {
                    continue;
                }

                int k = i - 1;
                int v = j - 1;
                while (k >= 0 && v >= 0)
                {
                    if (CaroResult[v * MAX_COLUMN + k] == -1)
                    {
                        TypeLine = 1;
                        EndGamePoint = j * MAX_COLUMN + i;
                        int m = i;
                        int n = j;
                        while (m < MAX_COLUMN && n < MAX_COLUMN)
                        {
                            if (CaroResult[n * MAX_COLUMN + m] == IsOwner)
                            {
                                ListCellWin.add(n * MAX_COLUMN + m);
                                m++;
                                n++;
                            } else
                            {
                                break;
                            }
                        }
                        return true;
                    }
                    if (CaroResult[v * MAX_COLUMN + k] != IsOwner)
                    {
                        break;
                    }
                    k--;
                    v--;
                }
                k = i + 5;
                v = j + 5;
                while (k < MAX_COLUMN && v < MAX_COLUMN)
                {
                    if (CaroResult[v * MAX_COLUMN + k] == -1)
                    {
                        TypeLine = 1;
                        EndGamePoint = j * MAX_COLUMN + i;
                        int m = i;
                        int n = j;
                        while (m < MAX_COLUMN && n < MAX_COLUMN)
                        {
                            if (CaroResult[n * MAX_COLUMN + m] == IsOwner)
                            {
                                ListCellWin.add(n * MAX_COLUMN + m);
                                m++;
                                n++;
                            } else
                            {
                                break;
                            }
                        }
                        return true;
                    }
                    if (CaroResult[v * MAX_COLUMN + k] != IsOwner)
                    {
                        break;
                    }
                    k++;
                    v++;
                }
            }
        }

        // Check duong cheo duoi len
        for (int i = x - 4; i < x + 1; i++)
        {
            if (i < 0 || i + 4 >= MAX_COLUMN)
            {
                continue;
            }

            int j = y - i + x;

            if (j - 4 < 0 || j >= MAX_ROW)
            {
                continue;
            }

            if (CaroResult[j * MAX_COLUMN + i] == IsOwner
                    && CaroResult[(j - 1) * MAX_COLUMN + i + 1] == IsOwner
                    && CaroResult[(j - 2) * MAX_COLUMN + i + 2] == IsOwner
                    && CaroResult[(j - 3) * MAX_COLUMN + i + 3] == IsOwner
                    && CaroResult[(j - 4) * MAX_COLUMN + i + 4] == IsOwner)
            {
                if (i == 0 || j == MAX_COLUMN - 1 || i + 5 == MAX_COLUMN || j - 4 == 0)
                {

                    if (i == 0)
                    {
                        if (j > 4)
                        {
                            if (CaroResult[(j - 5) * MAX_COLUMN + i + 5] == IsOwner)
                            {
                                continue;
                            }
                        }
                    }

                    if (j == MAX_COLUMN - 1)
                    {
                        if (i < MAX_COLUMN - 5)
                        {
                            if (CaroResult[(j - 5) * MAX_COLUMN + i + 5] == IsOwner)
                            {
                                continue;
                            }
                        }
                    }

                    if (i + 5 == MAX_COLUMN)
                    {
                        if (j < MAX_COLUMN - 1)
                        {
                            if (CaroResult[(j + 1) * MAX_COLUMN + i - 1] == IsOwner)
                            {
                                continue;
                            }
                        }
                    }

                    if (j - 4 == 0)
                    {
                        if (i > 0)
                        {
                            if (CaroResult[(j + 1) * MAX_COLUMN + i - 1] == IsOwner)
                            {
                                continue;
                            }
                        }
                    }

                    TypeLine = 3;
                    EndGamePoint = j * MAX_COLUMN + i;
                    int m = i;
                    int n = j;
                    while (m < MAX_COLUMN && n >= 0)
                    {
                        if (CaroResult[n * MAX_COLUMN + m] == IsOwner)
                        {
                            ListCellWin.add(n * MAX_COLUMN + m);
                            m++;
                            n--;
                        } else
                        {
                            break;
                        }
                    }
                    return true;
                }

                if (CaroResult[(j + 1) * MAX_COLUMN + i - 1] == IsOwner
                        || CaroResult[(j - 5) * MAX_COLUMN + i + 5] == IsOwner)
                {
                    continue;
                }

                int k = i - 1;
                int v = j + 1;
                while (k >= 0 && v < MAX_COLUMN)
                {
                    if (CaroResult[v * MAX_COLUMN + k] == -1)
                    {
                        TypeLine = 3;
                        EndGamePoint = j * MAX_COLUMN + i;
                        int m = i;
                        int n = j;
                        while (m < MAX_COLUMN && n >= 0)
                        {
                            if (CaroResult[n * MAX_COLUMN + m] == IsOwner)
                            {
                                ListCellWin.add(n * MAX_COLUMN + m);
                                m++;
                                n--;
                            } else
                            {
                                break;
                            }
                        }
                        return true;
                    }
                    if (CaroResult[v * MAX_COLUMN + k] != IsOwner)
                    {
                        break;
                    }
                    k--;
                    v++;
                }
                k = i + 5;
                v = j - 5;
                while (k < MAX_COLUMN && v >= 0)
                {
                    if (CaroResult[v * MAX_COLUMN + k] == -1)
                    {
                        TypeLine = 3;
                        EndGamePoint = j * MAX_COLUMN + i;
                        int m = i;
                        int n = j;
                        while (m < MAX_COLUMN && n >= 0)
                        {
                            if (CaroResult[n * MAX_COLUMN + m] == IsOwner)
                            {
                                ListCellWin.add(n * MAX_COLUMN + m);
                                m++;
                                n--;
                            } else
                            {
                                break;
                            }
                        }
                        return true;
                    }
                    if (CaroResult[v * MAX_COLUMN + k] != IsOwner)
                    {
                        break;
                    }
                    k++;
                    v--;
                }
            }
        }

        return false;
    }

    @Override
    public void EndGame()
    {

        if (Table.GameStage == CCommon.GS_RESULT)
        {
            return;
        }

        for (int i = 0; i < ListCellWin.size(); i++)
        {
            CDebug.Trace(this, " i === " + ListCellWin.get(i));
        }

        if (NumberClient == 1)
        {
            CClient ClientWin = Table.Owner;
            ClientWin.ExpAdd = 1;
            ClientWin.Ranking = 1;
            ClientWin.Level = CCommon.GetLevel(ClientWin.Exp);
            ClientWin.NewLevel = CCommon.GetLevel(ClientWin.Exp + ClientWin.ExpAdd);
            ClientWin.Exp += ClientWin.ExpAdd;
            ClientWin.AddGold(ClientWin.GoldAdd, "Caro");

            // Update
            ClientWin.UpdateScore();

            SaveData(ClientWin, null);

            CPacketWriter Packet = new CPacketWriter();
            Packet.PutID(MT_CARO_GAME_RESULT);
            Packet.PutInt(NumberClient);
            Packet.PutInt(0);
            CClient ClientOwner = Table.Owner;
            Packet.PutInt(ClientOwner.GetClientIndex());
            Packet.PutInt(ClientOwner.Ranking);
            Packet.PutInt(ClientOwner.Exp);
            Packet.PutInt(ClientOwner.ExpAdd);
            Packet.PutInt(ClientOwner.Level);
            Packet.PutInt(ClientOwner.NewLevel);
            Packet.PutDouble(ClientOwner.GetGold());
            Packet.PutDouble(ClientOwner.GoldAdd);
            Packet.PutDouble(ClientOwner.GoldBonus);
            Packet.PutLengthAndFlip();
            Table.SendAll(Packet);

        } else
        {
            if (IsTurn == 1)
            {
                CClient ClientWin = Table.Owner;
                ClientWin.ExpAdd = 2;
                ClientWin.GoldAdd = Table.GetAvaiTotalGold(ClientWin, Table.GoldBet * 0.95);
                ClientWin.WinAdd = 1;
                ClientWin.Ranking = 1;
                ClientWin.Level = CCommon.GetLevel(ClientWin.Exp);
                ClientWin.NewLevel = CCommon.GetLevel(ClientWin.Exp + ClientWin.ExpAdd);
                ClientWin.Exp += ClientWin.ExpAdd;
                ClientWin.AddGold(ClientWin.GoldAdd, "Caro");

                // Update
                ClientWin.UpdateScore();

                CClient ClientLost = Table.GetNextClient(Table.Owner);
                ClientLost.ExpAdd = 1;
                ClientLost.GoldAdd = -ClientLost.GetAvaiGoldAdd(Table.GoldBet);
                ClientLost.LostAdd = 1;
                ClientLost.Ranking = 2;
                ClientLost.Level = CCommon.GetLevel(ClientLost.Exp);
                ClientLost.NewLevel = CCommon.GetLevel(ClientLost.Exp + ClientLost.ExpAdd);
                ClientLost.Exp += ClientLost.ExpAdd;
                ClientLost.AddGold(ClientLost.GoldAdd, "Caro");

                // Update
                ClientLost.UpdateScore();

                // Lưu dữ liệu sau ván chơi
                SaveData(ClientWin, ClientLost);

                // Gửi kết quả
                CPacketWriter Packet = new CPacketWriter();
                Packet.PutID(MT_CARO_GAME_RESULT);

                Packet.PutInt(NumberClient);
                Packet.PutInt(1);
                int x = EndGamePoint % MAX_COLUMN;
                int y = EndGamePoint / MAX_COLUMN;
                //Packet.WriteInt(x);
                //Packet.WriteInt(y);
                //Packet.WriteInt(TypeLine);

                Packet.PutInt(ListCellWin.size());
                for (int i = 0; i < ListCellWin.size(); i++)
                {
                    Packet.PutInt(ListCellWin.get(i));
                }

                CClient ClientOwner = Table.Owner;
                Packet.PutInt(ClientOwner.GetClientIndex());
                Packet.PutInt(ClientOwner.Ranking);
                Packet.PutInt(ClientOwner.Exp);
                Packet.PutInt(ClientOwner.ExpAdd);
                Packet.PutInt(ClientOwner.Level);
                Packet.PutInt(ClientOwner.NewLevel);
                Packet.PutDouble(ClientOwner.GetGold());
                Packet.PutDouble(ClientOwner.GoldAdd);
                Packet.PutDouble(ClientOwner.GoldBonus);

                CClient Client = Table.GetNextClient(Table.Owner);
                Packet.PutInt(Client.GetClientIndex());
                Packet.PutInt(Client.Ranking);
                Packet.PutInt(Client.Exp);
                Packet.PutInt(Client.ExpAdd);
                Packet.PutInt(Client.Level);
                Packet.PutInt(Client.NewLevel);
                Packet.PutDouble(Client.GetGold());
                Packet.PutDouble(Client.GoldAdd);
                Packet.PutDouble(Client.GoldBonus);
                Packet.PutLengthAndFlip();
                Table.SendAll(Packet);
            } else if (IsTurn == 0)
            {
                CClient ClientWin = Table.GetNextClient(Table.Owner);
                ClientWin.ExpAdd = 2;
                ClientWin.GoldAdd = Table.GetAvaiTotalGold(ClientWin, Table.GoldBet * 0.95);
                ClientWin.WinAdd = 1;
                ClientWin.Ranking = 1;
                ClientWin.Level = CCommon.GetLevel(ClientWin.Exp);
                ClientWin.NewLevel = CCommon.GetLevel(ClientWin.Exp + ClientWin.ExpAdd);
                ClientWin.Exp += ClientWin.ExpAdd;
                ClientWin.AddGold(ClientWin.GoldAdd, "Caro");

                // Update
                ClientWin.UpdateScore();

                CClient ClientLost = Table.Owner;
                ClientLost.ExpAdd = 1;
                ClientLost.GoldAdd = -ClientLost.GetAvaiGoldAdd(Table.GoldBet);
                ClientLost.LostAdd = 1;
                ClientLost.Ranking = 2;
                ClientLost.Level = CCommon.GetLevel(ClientLost.Exp);
                ClientLost.NewLevel = CCommon.GetLevel(ClientLost.Exp + ClientLost.ExpAdd);
                ClientLost.Exp += ClientLost.ExpAdd;
                ClientLost.AddGold(ClientLost.GoldAdd, "Caro");

                // Update
                ClientLost.UpdateScore();

                // Lưu dữ liệu sau ván chơi
                SaveData(ClientWin, ClientLost);

                // Gửi kết quả
                CPacketWriter Packet = new CPacketWriter();
                Packet.PutID(MT_CARO_GAME_RESULT);

                Packet.PutInt(NumberClient);
                Packet.PutInt(2);
                int x = EndGamePoint % MAX_COLUMN;
                int y = EndGamePoint / MAX_COLUMN;
                //Packet.WriteInt(x);
                //Packet.WriteInt(y);
                //Packet.WriteInt(TypeLine);

                Packet.PutInt(ListCellWin.size());
                for (int i = 0; i < ListCellWin.size(); i++)
                {
                    Packet.PutInt(ListCellWin.get(i));
                }

                CClient ClientOwner = Table.Owner;
                Packet.PutInt(ClientOwner.GetClientIndex());
                Packet.PutInt(ClientOwner.Ranking);
                Packet.PutInt(ClientOwner.Exp);
                Packet.PutInt(ClientOwner.ExpAdd);
                Packet.PutInt(ClientOwner.Level);
                Packet.PutInt(ClientOwner.NewLevel);
                Packet.PutDouble(ClientOwner.GetGold());
                Packet.PutDouble(ClientOwner.GoldAdd);
                Packet.PutDouble(ClientOwner.GoldBonus);

                CClient Client = Table.GetNextClient(Table.Owner);
                Packet.PutInt(Client.GetClientIndex());
                Packet.PutInt(Client.Ranking);
                Packet.PutInt(Client.Exp);
                Packet.PutInt(Client.ExpAdd);
                Packet.PutInt(Client.Level);
                Packet.PutInt(Client.NewLevel);
                Packet.PutDouble(Client.GetGold());
                Packet.PutDouble(Client.GoldAdd);
                Packet.PutDouble(Client.GoldBonus);
                Packet.PutLengthAndFlip();
                Table.SendAll(Packet);
            } else
            {
                CClient ClientWin = Table.GetNextClient(Table.Owner);
                ClientWin.ExpAdd = 1;
                //ClientWin.GoldAdd = Table.GetAvaiTotalGold(ClientWin, Table.GoldBet * 0.95);
                //ClientWin.WinAdd = 1;
                ClientWin.Ranking = 0;
                ClientWin.Level = CCommon.GetLevel(ClientWin.Exp);
                ClientWin.NewLevel = CCommon.GetLevel(ClientWin.Exp + ClientWin.ExpAdd);
                ClientWin.Exp += ClientWin.ExpAdd;
                ClientWin.AddGold(ClientWin.GoldAdd, "Caro");

                // Update
                ClientWin.UpdateScore();

                CClient ClientLost = Table.Owner;
                ClientLost.ExpAdd = 1;
                ClientLost.Ranking = 0;
                //ClientLost.GoldAdd = -ClientLost.GetAvaiGoldAdd(Table.GoldBet);
                //ClientLost.LostAdd = 1;
                ClientLost.Level = CCommon.GetLevel(ClientLost.Exp);
                ClientLost.NewLevel = CCommon.GetLevel(ClientLost.Exp + ClientLost.ExpAdd);
                ClientLost.Exp += ClientLost.ExpAdd;
                ClientLost.AddGold(ClientLost.GoldAdd, "Caro");

                // Update
                ClientLost.UpdateScore();

                // Lưu dữ liệu sau ván chơi
                SaveData(ClientWin, ClientLost);

                // Gửi kết quả
                CPacketWriter Packet = new CPacketWriter();
                Packet.PutID(MT_CARO_GAME_RESULT);

                Packet.PutInt(NumberClient);
                Packet.PutInt(3);

                CClient ClientOwner = Table.Owner;
                Packet.PutInt(ClientOwner.GetClientIndex());
                Packet.PutInt(ClientOwner.Ranking);
                Packet.PutInt(ClientOwner.Exp);
                Packet.PutInt(ClientOwner.ExpAdd);
                Packet.PutInt(ClientOwner.Level);
                Packet.PutInt(ClientOwner.NewLevel);
                Packet.PutDouble(ClientOwner.GetGold());
                Packet.PutDouble(ClientOwner.GoldAdd);
                Packet.PutDouble(ClientOwner.GoldBonus);

                CClient Client = Table.GetNextClient(Table.Owner);
                Packet.PutInt(Client.GetClientIndex());
                Packet.PutInt(Client.Ranking);
                Packet.PutInt(Client.Exp);
                Packet.PutInt(Client.ExpAdd);
                Packet.PutInt(Client.Level);
                Packet.PutInt(Client.NewLevel);
                Packet.PutDouble(Client.GetGold());
                Packet.PutDouble(Client.GoldAdd);
                Packet.PutDouble(Client.GoldBonus);
                
                Packet.PutLengthAndFlip();
                Table.SendAll(Packet);
            }
        }

        Table.SetGameStage(CCommon.GS_RESULT, TIME_CARO_RESULT);

    }

    private String GenerateGameId()
    {
        String GameId = "";
        GameId += "G" + Table.GetIndex();
        GameId += "T" + (Table.GetIndex() + 1);
        GameId += "D" + new Date();

        return GameId;
    }

    // Lưu lịch sử ván chơi
    private void SaveData(CClient Winner, CClient Looser)
    {
    }

    @Override
    public void OnClientExit(CClient Client)
    {
        if (Table.GameStage == CCommon.GS_PLAYING)
        {
            CCommon.UpdateScore(Client.AccountId, -Table.GoldBet * 2, 0, CCommon.APP_CARO, 0, 0, 0, 1);
            if (Table.Owner == Client)
            {
                Table.Owner = Table.GetNextClient(Client);
            }
            NumberClient = 1;
            EndGame();
        }
    }

    @Override
    public void SendViewerData(CClient Viewer)
    {
    }

    @Override
    public boolean CanJoinTable(CClient Client)
    {
        return true;
    }
}
